package com.silverhaze.diamond.client.data.dao;

import com.silverhaze.commons.db.datasource.ObjectEntity;
import com.silverhaze.commons.utils.collections.list.MetaList;
import com.silverhaze.diamond.client.ui.event.UIClientEventDispatcher;
import com.silverhaze.diamond.client.ui.event.UIEventDispatcherListener;
import com.silverhaze.diamond.client.utils.db.ServiceDataSource;
import com.silverhaze.diamond.common.entity.Customer;
import com.silverhaze.diamond.common.entity.Detail;
import com.silverhaze.diamond.common.entity.Service;
import com.silverhaze.diamond.common.entity.SystemUser;
import com.silverhaze.diamond.common.event.UIEvent;
import com.silverhaze.diamond.common.event.UIEventClassChanged;
import com.silverhaze.diamond.common.event.UIEventEntityChanged;

import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * SystemUser: Babanin
 * Date: 08.07.2008
 * Time: 22:49:25
 */
public final class DAOLocator implements UIEventDispatcherListener {

    private static DAOLocator instance;

    private Map<Class<? extends ObjectEntity>, Map<Long, ObjectEntity>> cache;
    private final ServiceDataSource dataSource = ServiceDataSource.getInstance();

    public DAOLocator() {
        cache = new HashMap<Class<? extends ObjectEntity>, Map<Long, ObjectEntity>>();

        cache.put(Detail.class, load(Detail.class));
        cache.put(Service.class, load(Service.class));
        cache.put(Customer.class, load(Customer.class));
        cache.put(SystemUser.class, load(SystemUser.class));

        UIClientEventDispatcher.getInstance().subscribe(this, UIEventEntityChanged.class);
    }

    private Map<Long, ObjectEntity> load(Class<? extends ObjectEntity> clazz) {
        MetaList<? extends ObjectEntity> entities = dataSource.get(clazz);
        Map<Long, ObjectEntity> result = new HashMap<Long, ObjectEntity>();

        for (ObjectEntity entity : entities) {
            try {
                result.put((Long) entity.getClass().getMethod("getId", new Class[0]).invoke(entity), entity);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    public long add(ObjectEntity entity) {
        return dataSource.persist(entity);
    }

    public void update(ObjectEntity entity) {
//        if (entity instanceof Service) {
//            dataSource.updateService((Service) entity);
//        } else {
        dataSource.update(entity);
//        }
    }

    public void remove(ObjectEntity entity) {
        dataSource.delete(entity);
    }

    public List<ObjectEntity> getDetails() {
        Map<Long, ObjectEntity> longObjectEntityMap = cache.get(Detail.class);
        return new ArrayList<ObjectEntity>(longObjectEntityMap.values());
    }

    public List<ObjectEntity> getUsers() {
        Map<Long, ObjectEntity> longObjectEntityMap = cache.get(SystemUser.class);
        return new ArrayList<ObjectEntity>(longObjectEntityMap.values());
    }

    public List<ObjectEntity> getServices() {
        Map<Long, ObjectEntity> longObjectEntityMap = cache.get(Service.class);
        return new ArrayList<ObjectEntity>(longObjectEntityMap.values());
    }

    public List<Service> getServices(Detail detail) {
        List<Service> result = new ArrayList<Service>();
        List<Service> list = dataSource.getBeans(Service.class);

        for (Service service : list) {
            if (service.getUsedDetailes().contains(detail)) {
                result.add(service);
            } else if (service.getBrokenDetailes().contains(detail)) {
                result.add(service);
            }
        }

        return result;
    }

    public List<Service> getServices(Customer customer) {
        List<Service> result = new ArrayList<Service>();
        List<Service> list = dataSource.getBeans(Service.class);

        for (Service service : list) {
            if (service.getOwner().equals(customer)) {
                result.add(service);
            }
        }

        return result;
    }

    public List<ObjectEntity> getCustomers() {
        Map<Long, ObjectEntity> longObjectEntityMap = cache.get(Customer.class);
        return new ArrayList<ObjectEntity>(longObjectEntityMap.values());
    }

    public void addEntities(Set<? extends ObjectEntity> entities) {
        for (ObjectEntity entity : entities) {
            add(entity);
        }
    }

    @Override
    public void handleEvent(UIEvent event) {
        if (event instanceof UIEventEntityChanged) {
            UIEventEntityChanged entityChanged = (UIEventEntityChanged) event;

            Map<Long, ObjectEntity> objectEntityMap = cache.get(event.getChangedEntityClass());
            if (objectEntityMap == null) {
                objectEntityMap = new HashMap<Long, ObjectEntity>();
                cache.put(event.getChangedEntityClass(), objectEntityMap);
            }

            switch (entityChanged.getType()) {
                case PERSIST:
                case UPDATE:
                    objectEntityMap.put(entityChanged.getEntity().getId(), entityChanged.getEntity());
                    break;
                case DELETE:
                    objectEntityMap.remove(entityChanged.getEntity().getId());
                    break;
            }

        } else if (event instanceof UIEventClassChanged) {
            UIEventClassChanged classChanged = (UIEventClassChanged) event;
            Class<? extends ObjectEntity> changedEntityClass = classChanged.getChangedEntityClass();

            cache.put(changedEntityClass, load(classChanged.getChangedEntityClass()));
        }
    }

    public static DAOLocator getInstance() {
        if (instance == null) {
            instance = new DAOLocator();
        }

        return instance;
    }
}
